﻿using ErrorOr;
using Gnivc.CarDealership.Api.Application.Abstractions;
using Gnivc.CarDealership.Api.Application.Abstractions.Repositories;
using Gnivc.CarDealership.Api.Application.Dtos;
using Gnivc.CarDealership.Api.Domain.Entities;
using Mapster;
using Microsoft.AspNetCore.Mvc;

namespace Gnivc.CarDealership.Api.Controllers;

[Route("api/[controller]")]
public class PricesController : ApiController
{
    private readonly IVehicleRepository _vehicleRepository;
    private readonly IPriceRepository _priceRepository;
    private readonly IUnitOfWork _unitOfWork;

    public PricesController(
        IVehicleRepository vehicleRepository, 
        IPriceRepository priceRepository, 
        IUnitOfWork unitOfWork)
    {
        _vehicleRepository = vehicleRepository;
        _priceRepository = priceRepository;
        _unitOfWork = unitOfWork;
    }

    [HttpGet("{vehicleId}")]
    public async Task<IResult> GetPricesByVehicle(Guid vehicleId)
    {
        var getVehicleResult = 
            await _vehicleRepository.GetByIdAsync(vehicleId);

        if (getVehicleResult.IsError)
            return Problem(getVehicleResult.Errors);

        var getPriceResult = 
            await _priceRepository.GetAllByVehicleAsync(vehicleId);

        if(getPriceResult.IsError)
            return Problem(getPriceResult.Errors);

        var prices = getPriceResult.Value!;

        return Results.Ok(prices.Select(x => new PriceDto
        {
            PriceId = x.Id,
            StartDate = x.StartDate,
            EndDate = x.EndDate,
            Value = x.Value
        }));
    }

    [HttpPost("create")]
    public async Task<IResult> CreatePrice(
        [FromQuery] Guid vehicleId,
        [FromQuery] decimal value)
    {
        var getVehicleResult =
            await _vehicleRepository.GetByIdAsync(vehicleId);

        if (getVehicleResult.IsError)
            return Problem(getVehicleResult.Errors);

        var getCurrentPriceResult = 
            await _priceRepository.GetCurrentPriceAsync(vehicleId);

        if(getCurrentPriceResult.IsError)
            return Problem(getCurrentPriceResult.Errors);

        var currentPrice = getCurrentPriceResult.Value!;

        currentPrice.EndDate = DateTime.UtcNow;

        var price = new Price(
            Guid.NewGuid(),
            value,
            getVehicleResult.Value!);

        await _unitOfWork.BeginTransactionAsync();

        try
        {
            await _priceRepository.UpdateAsync(currentPrice);
            await _priceRepository.AddAsync(price);
            await _unitOfWork.CommitTransactionAsync();
        }
        catch (Exception ex)
        {
            await _unitOfWork.RollbackTransactionAsync();
            var errors = new List<Error>()
            {
                Error.Failure(description: ex.Message)
            };
            return Problem(errors);
        }

        return Results.Ok(new PriceDto
        {
            PriceId = price.Id,
            StartDate = price.StartDate,
            EndDate = price.EndDate,
            Value = price.Value
        });
    }
}
